#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main()
{
    int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(listen_sock < 0)
    {
        perror("socket");
        return 0;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(28989);
    addr.sin_addr.s_addr = inet_addr("0.0.0.0"); //0.0.0.0表示本地所有的网卡地址

    int ret = bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0)
    {
        perror("bind");
        return 0;
    }

    ret = listen(listen_sock, 1);// 1表示内核中已完成连接队列的大小，决定了服务端的并发连接数
    if(ret < 0)
    {
        perror("listen");
        return 0;
    }

     while(1)
     {
         //接受连接
         //accept接收的是客户端的地址信息，创建客户端的地址信息结构
         struct sockaddr_in cli_addr;
         socklen_t cli_addrlen = sizeof(cli_addr);

         int newsockfd = accept(listen_sock, (struct sockaddr*)&cli_addr, &cli_addrlen);//接收新连接的返回值是新连接的套接字描述符
        if(newsockfd < 0)
        {
            perror("accept");
            continue;  //接收失败，继续接收连接
        }

        printf("accept new connect from client %s : %d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));


        //已经建立连接，此时服务端与客户端可以交互，可以发送数据，也可以接收数据
        
        //接收数据
        char buf[1024] = {0};
        ssize_t recv_size = recv(newsockfd, buf, sizeof(buf) - 1, 0); //recv函数接收的是新连接的套接字newsockfd，返回值类型是ssize_t。最后一个参数0表示阻塞接收。
        if(recv_size < 0) //函数调用出错了
        {
            perror("recv");
            continue; //继续接收
        }
        else if(recv_size == 0) //表示对端关闭连接
        {
            printf("peer close connet\n");
            close(newsockfd); //对端把连接套接字关闭掉了，自己也把对应的连接套接字关闭
            continue;  //再去接收新的连接
        }

        //下面就是recv_size > 0的情况，就是接收到的情况
        printf("buf is : %s\n", buf);

        //发送数据
        memset(buf, '\0', sizeof(buf));
        strcpy(buf,"i am server!!!\n"); //strcpy不是安全函数
        ssize_t send_size = send(newsockfd, buf, strlen(buf), 0); //最后的0表示阻塞发送
        if(send_size <= 0)
        {
            perror("send"); 
            continue;
        }
        else 
        {
            printf("发送的字节数是：%zu\n", send_size); //ssize_t 用 %zu 输出
        }
     }

    close(listen_sock);  //最后要把侦听套接字关掉

    return 0;
}
